#region PrivateFunctions

function Get-RelativePath {
	[CmdletBinding()]
	param(
		[Parameter(Mandatory=$true, Position=0)]
		[string]$Folder, 
		[Parameter(Mandatory=$true, Position=1, ValueFromPipelineByPropertyName=$true)]
		[Alias("FullName")]
		[string]$FilePath,
		[switch]$Resolve
	)
	process {
		$from = $Folder = split-path $Folder -NoQualifier -Resolve:$Resolve
		$to = $filePath = split-path $filePath -NoQualifier -Resolve:$Resolve

		while($from -and $to -and ($from -ne $to)) {
			if($from.Length -gt $to.Length) {
				$from = split-path $from
			} else {
				$to = split-path $to
			}
		}

		$filepath = $filepath -replace "^"+[regex]::Escape($to)+"\\"
		$from = $Folder
		while($from -and $to -and $from -gt $to ) {
			$from = split-path $from
			$filepath = join-path ".." $filepath
		}
		Write-Output $filepath
	}
}

function Test-ConsolePrintLog{
	[CmdletBinding()]
	param(
		[Parameter(Mandatory=$false)]
		$HostName = $Host.Name,
		[Parameter(Mandatory=$false)]
		[log4net.Core.LogImpl]
		$Logger = @( $PoshLoggerInfo.DefaultLogger )[0]
	)
	
	$InHostList = $False
	$ConsoleOut = $False
	
	#Check if current host is in our list of problem hosts
	#if not in the list return false
	if( Test-Path "$PSScriptRoot\config\UseNativeWriteHost.xml" ){
		[xml]$ProblemHosts = Get-Content "$PSScriptRoot\config\UseNativeWriteHost.xml"
		$ProblemHosts.UseNativeWriteHost.PartialHostName | Foreach-Object { 
			if( $Host.Name -like "*$_*" ){
				$InHostList = $True
			}
		}
	}
	if( -not $InHostList ){
		return $False
	}
	
	#If the host was is the list check to se if an appender with the target Console.Out is defined
	#if no Console.Out is targeted then return false
	$Logger.Logger.Appenders | Foreach-Object { 
		if( $_.Target -eq "Console.Out" ){
			$ConsoleOut = $True
		}
	}
	if( -not $ConsoleOut ){
		return $False
	}
	
	#If current host was in list and Console.Out has been targeted
	#return true ( use the native Write Host to write to the console
	if( $ConsoleOut -and $InHostList ){
		return $True
	}
}

function Get-LogString{
	param(
		$LoggerName,
		$Level,
		$Message
	)
	$LogDate = Get-Date -f 'MM-dd-yyyy HH:mm:ss'
	Write-Output "$LogDate $Level $LoggerName [$( $PoshLoggerInfo.CurrentLogContext )] - $Message"
	
}

#endregion

<#
	.SYNOPSIS
	Get an existing Logger by name, or create a new logger
	.DESCRIPTION
	Returns a logger matching the name (wildcards allowed) provided. 
	
	If the logger already exists, it is returned with it's settings as-is, unless the -Force switch is specified, in which case the new settings are used
	
	If only one logger matches the name, that logger becomes the new default logger.
	
	.PARAMETER Name
	The name of the logger to find or create. If no name is specified, all existing loggers are returned.
	
	.PARAMETER Level
	The level at which to log in this new logger. Defaults to "DEBUG" 
	Possible levels are as follows (each level includes all levels above it):
	
	ERROR
	WARN
	INFO
	DEBUG
	
	.PARAMETER MessagePattern
	The pattern for loggers which use patterns (mostly the file loggers). Defaults to: 
	"%date %-5level %logger [%property{NDC}] - %message%newline"
	
	For a complete list of possible pattern names, see:
	http://logging.apache.org/log4net/release/sdk/log4net.Layout.PatternLayout.html
	
	.PARAMETER Folder
	The folder where log files are kept. Defaults to the path returned by Get-Location at the time of creating the Logger.
	NOTE: if the specified folder does not exist, it will be created
	
	.PARAMETER EmailTo
	An email address to send WARNING or above messages to. REQUIRES that your $PSEmailServer variable be set
	.PARAMETER Console
	Creates a colored console logger
	.PARAMETER EventLog
	Creates an EventLog logger
	.PARAMETER TraceLog
	Creates a .Net Trace logger
	.PARAMETER DebugLog
	Creates a .Net Debug logger
	.PARAMETER FileLog
	Creates a file logger. Note the LogLock parameter!
	.PARAMETER RollingFileLog
	Creates a rolling file logger with a max size of 250KB. Note the LogLock parameter!   
	.PARAMETER XmlLog
	Creates an Xml-formatted file logger. Note the LogLock parameter!
	
	Note: the XmlLog will output an XML Header and will add a footer when the logger is closed.
	This results in a log file which is readable in xml viewers like IE, particularly if you have a copy of the XSLT stylesheet for Log4Net (http://poshcode.org/1750) named log4net.xslt in the same folder with the log file.
	
	WARNING: Because of this, it does not APPEND to the file, but overwrites it each time you create the logger.
	.PARAMETER RollingXmlLog
	Creates a rolling file Xml logger with a max size of 500KB. Note the LogLock parameter!
	
	Note: the rolling xml logger cannot create "valid" xml because it appends to the end of the file (and therefore can't guarantee the file is well-formed XML).
	In order to get a valid Xml file, you can use a "*View.xml" file with contents like this (which this script will create):
	
	<?xml version="1.0" ?>
	<?xml-stylesheet type="text/xsl" href="log4net.xslt"?>
	<!DOCTYPE events [<!ENTITY data SYSTEM "PowerShellLogger.xml">]>
	<log4net:events version="1.2" xmlns:log4net="http://logging.apache.org/log4net/schemas/log4net-events-1.2">
		&data;
	</log4net:events>
	.PARAMETER LogLock
	Determines the type of file locking used (defaults to SHARED): 
	SHARED is the "MinimalLocking" model which opens the file once for each AcquireLock/ReleaseLock cycle, thus holding the lock for the minimal amount of time. This method of locking is considerably slower than...
	
	EXCLUSIVE is the "ExclusiveLocking" model which opens the file once for writing and holds it open until the logger is closed, maintaining an exclusive lock on the file the whole time..
	.PARAMETER UdpSend
	Creates an UdpAppender which sends messages to the localmachine port 8080
	We'll probably tweak this in a future release, but for now if you need to change that you need to edit the script
	.PARAMETER ChainsawSend
	Like UdpSend, creates an UdpAppender which sends messages to the localmachine port 8080. 
	This logger uses the log4j xml formatter which is somewhat different than the default, and uses their namespace.   
	.PARAMETER Force
	Force resetting the logger switches even if the logger already exists
#>
function Get-Logger {
	[CmdletBinding()]
	param( 
		[Parameter(Mandatory=$false, Position=0)]
		[string]
		$Name = "PoshLogger",
		[Parameter(Mandatory=$false)]
		[ValidateSet('DEBUG','INFO','WARN','ERROR')]
		[string]
		$Level = "INFO",
		[Parameter(Mandatory=$false)]
		$MessagePattern = "%date{MM-dd-yyyy HH:mm:ss} %-5level %logger [%property{NDC}] - %message%newline",
		[Parameter(Mandatory=$false)]
		[string]
		$Folder = $( Get-Location ), 
		[switch]
		$Force, 
		[switch]
		$ConsoleLog, 
		[switch]
		$EventLog, 
		[switch]
		$TraceLog, 
		[switch]
		$DebugLog, 
		[switch]
		$FileLog, 
		[switch]
		$RollingFileLog, 
		[switch]
		$XmlLog, 
		[switch]
		$RollingXmlLog, 
		[switch]
		$UdpSend, 
		[switch]
		$ChainsawSend,
		[Parameter(Mandatory=$false, Position=99)]
		[ValidateSet("Shared","Exclusive")]
		[String]
		$LogLock = "Shared"
	)
	## Make sure the folder exists
	if(!(Test-Path $Folder)) {
		New-Item -ItemType Directory -Path $Folder -Force
	}

	[log4net.LogManager]::GetCurrentLoggers() | Where-Object { $_.Logger.Name -like $Name } | Tee-Object -Variable Loggers
	if((!$Loggers -or $Force) -and !$Name.Contains('*')) {
		$AppenderRefs = ''
		
		if($LogLock -eq "Shared") { 
			$LockMode = "MinimalLock"
		} 
		else {
			$LockMode = "ExclusiveLock"
		}
		
		$xslt = ""
		if(Test-Path $PSScriptRoot\xml\PoshLogger.xslt) {
			$xslt = @"
<?xml-stylesheet type="text/xsl" href="$(Get-RelativePath $Folder $PSScriptRoot\xml\PoshLogger.xslt)"?>
"@
		}


		if($EventLog) { $AppenderRefs += "<appender-ref ref=""EventLogAppender"" />`n" }
		if($TraceLog) { $AppenderRefs += "<appender-ref ref=""TraceAppender"" />`n" }
		if($DebugLog){ $AppenderRefs += "<appender-ref ref=""DebugAppender"" />`n" }
		if($FileLog) { $AppenderRefs += "<appender-ref ref=""FileAppender"" />`n" }
		if($RollingFileLog) { $AppenderRefs += "<appender-ref ref=""RollingFileAppender"" />`n" }
		if($UdpSend) { $AppenderRefs += "<appender-ref ref=""UdpAppender"" />`n" } 
		if($ChainsawSend) { $AppenderRefs += "<appender-ref ref=""UdpLog4JAppender"" />`n" } 
		if($XmlLog) { $AppenderRefs += "<appender-ref ref=""XmlAppender"" />`n" } 
		if($RollingXmlLog) { $AppenderRefs += "<appender-ref ref=""RollingXmlAppender"" />`n"
			Set-Content "${Folder}\${Name}View.Xml" @"
<?xml version="1.0" ?>
$xslt
<!DOCTYPE events [<!ENTITY data SYSTEM "$Name.xml">]>
<events version="1.2" xmlns:log4net="http`://logging.apache.org/log4net/schemas/log4net-events-1.2">
<logname>$Name</logname>
   &data;
</events>
"@ 
		}
		$xslt = $xslt -replace "<","&lt;" -replace ">","&gt;" -replace '"',"'"

		if($ConsoleLog -or ($AppenderRefs.Length -eq 0)) { $AppenderRefs += "<appender-ref ref=""ColoredConsoleAppender"" />`n" }

		[log4net.LogManager]::GetLogger($Name) | Tee-Object -Variable Script:Logger | where { $Loggers -notcontains $_ }

		[xml]$config = @"
<log4net>
   <appender name="ColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender">
      <mapping>
         <level value="FATAL" />
         <foreColor value="Red, HighIntensity" />
         <backColor value="White, HighIntensity" />
      </mapping>
      <mapping>
         <level value="ERROR" />
         <foreColor value="Red, HighIntensity" />
      </mapping>
      <mapping>
         <level value="DEBUG" />
         <foreColor value="Green, HighIntensity" />
      </mapping>
      <mapping>
         <level value="INFO" />
         <foreColor value="Cyan, HighIntensity" />
      </mapping>
      <mapping>
         <level value="WARN" />
         <foreColor value="Yellow, HighIntensity" />
      </mapping>
      <layout type="log4net.Layout.PatternLayout">
         <conversionPattern value="$MessagePattern" />
      </layout>
   </appender>
   <appender name="EventLogAppender" type="log4net.Appender.EventLogAppender" >
      <applicationName value="$Name" />
      <layout type="log4net.Layout.PatternLayout">
         <conversionPattern value="$MessagePattern" />
      </layout>
   </appender>
   <appender name="TraceAppender" type="log4net.Appender.TraceAppender">
      <layout type="log4net.Layout.PatternLayout">
         <conversionPattern value="$MessagePattern" />
      </layout>
   </appender>
   <appender name="DebugAppender" type="log4net.Appender.DebugAppender">
      <layout type="log4net.Layout.PatternLayout">
         <conversionPattern value="$MessagePattern" />
      </layout>
   </appender>
   <appender name="FileAppender" type="log4net.Appender.FileAppender">
      <file value="$Folder\$Name.Log" />
      <appendToFile value="true" />
      <lockingModel type="log4net.Appender.FileAppender+$LockMode" />
      <layout type="log4net.Layout.PatternLayout">
         <conversionPattern value="$MessagePattern" />
      </layout>
   </appender>
   <appender name="XmlAppender" type="log4net.Appender.FileAppender">
      <file value="$Folder\$Name.xml" />
      <appendToFile value="false" />
      <lockingModel type="log4net.Appender.FileAppender+$LockMode" />
      <layout type="log4net.Layout.XmlLayout">
         <Header value="&lt;?xml version='1.0' ?&gt;
$xslt
&lt;events version='1.2' xmlns='http`://logging.apache.org/log4net/schemas/log4net-events-1.2'&gt;
"/>
         <Footer value="&lt;/events&gt;"/>
      </layout>
   </appender>
   <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
      <file value="$Folder\$Name.Log" />
      <appendToFile value="true" />
      <maximumFileSize value="250KB" />
      <maxSizeRollBackups value="2" />
      <lockingModel type="log4net.Appender.FileAppender+$LockMode" />
      <layout type="log4net.Layout.PatternLayout">
         <conversionPattern value="$MessagePattern" />
      </layout>
   </appender>
   <appender name="RollingXmlAppender" type="log4net.Appender.RollingFileAppender">
      <file value="$Folder\$Name.xml" />
      <appendToFile value="true" />
      <maximumFileSize value="500KB" />
      <maxSizeRollBackups value="2" />
      <lockingModel type="log4net.Appender.FileAppender+$LockMode" />
      <layout type="log4net.Layout.XmlLayout">
         <prefix value="" />
      </layout>
   </appender>
   <appender name="UdpAppender" type="log4net.Appender.UdpAppender">
      <RemoteAddress value="localhost" />
      <RemotePort value="8080" />
      <Encoding value="utf-8" />
      <layout type="log4net.Layout.XmlLayout">
         <Prefix value="" />
      </layout>
      <threshold value="DEBUG" />
   </appender>
   <appender name="UdpLog4JAppender" type="log4net.Appender.UdpAppender">
      <RemoteAddress value="127.0.0.1" />
      <RemotePort value="8080" />
      <Encoding value="utf-8" />
      <layout type="log4net.Layout.XmlLayoutSchemaLog4j, log4net" />
      <threshold value="DEBUG" />
   </appender>
   <appender name="SmtpAppender" type="log4net.Appender.SmtpAppender">
      <to value="$EmailTo" />
      <from value="PoshLogger@$Domain" />
      <subject value="PowerShell Logger Message" />
      <smtpHost value="$PSEmailServer" />
      <bufferSize value="512" />
      <lossy value="true" />
      <evaluator type="log4net.Core.LevelEvaluator">
         <threshold value="WARN"/>
      </evaluator>
      <layout type="log4net.Layout.PatternLayout">
         <conversionPattern value="%newline$MessagePattern%newline%newline" />
      </layout>
   </appender>
   <root>
      <level value="DEBUG" />
   </root>
   <logger name="$Name">
      <level value="$Level" />
      $AppenderRefs
   </logger>
</log4net>
"@
		$config.Save("$PSScriptRoot\config\currentlogger.config")
		[log4net.Config.XmlConfigurator]::Configure( $config.log4net )
	} 
	elseif($Loggers -and @($Loggers).Count -eq 1) {
		$script:UseLogger = @($Loggers)[0]
	}
}

<#
	.SYNOPSIS
		Set the default Logger used by the exported commands
	.DESCRIPTION
		Sets the default Logger used by the exported commands when a Logger is not passed in as a parameter.
		The Logger param must be a log4net.Core.LogImpl object as is returned by Get-Logger 
	.PARAMETER  Logger
		The Logger to use as default
	.EXAMPLE
		PS C:\> Set-DefaultLogger -Logger ( Get-Logger )
	.INPUTS
		log4net.Core.LogImpl
#>
function Set-DefaultLogger{
	[CmdletBinding()]
	param(
		[Parameter(Mandatory=$True)]
		[log4net.Core.LogImpl]
		$Logger
	)
	$PoshLoggerInfo.DefaultLogger = $Logger
}

<#
	.SYNOPSIS
		Get the current default logger
	.DESCRIPTION
		returns a handle to the current default logger
	.EXAMPLE
		PS C:\> Get-DefaultLogger
#>
function Get-DefaultLogger{
	Write-Output $PoshLoggerInfo.DefaultLogger
}

<#
	.SYNOPSIS
		Closes instance(s) of loggers
	.DESCRIPTION
		A function the closes or stops the PoshLogger loggers
	.PARAMETER  Logger
		The Logger to Stop and Close
	.EXAMPLE
		PS C:\> $MyLogger | Close-Logger
	.EXAMPLE
		PS C:\> Close-Logger -Logger $MyLogger
	.EXAMPLE
		PS C:\> Get-Logger -Name '*' | Close-Logger
	.INPUTS
		log4net.Core.LogImpl
	.OUTPUTS
		null
#>
function Close-Logger {
	param(
		[Parameter(Mandatory=$false, ValueFromPipeline=$true)]
		[log4net.Core.LogImpl]
		$Logger
	)
	process {
		
		if($Logger) {
			$Logger.Logger.CloseNestedAppenders()
			$Logger.Logger.RemoveAllAppenders()
		} else {
			[log4net.LogManager]::Shutdown()
		}
	}
}

<#
	.SYNOPSIS
		Insert the Context of the log message
	.DESCRIPTION
		The log messages contain a field ( NDC ) for the log context.
		This field can be used to insert the function name, script name, 
		or any other string to help trace were the log message was written.
		THERE CAN ONLY BE ONE. IF YOU PUSH a Value the previous Value is removed
	.PARAMETER  Name
		The string to insert into the NDC context field 
	.EXAMPLE
		PS C:\> Push-LogContext -Name 'Get-SqlData'
	.INPUTS
		System.String
	.OUTPUTS
		null
#>
function Push-LogContext {
	[CmdletBinding()]
	param( 
		[Parameter(Mandatory=$true)]
		[string]
		$Name
	)
	Pop-LogContext
	$PoshLoggerInfo.CurrentLogContext = "$Name"
	[log4net.NDC]::Push($Name) | Out-Null
}

<#
	.SYNOPSIS
		Removes the NDC string that is currently being used in the log.
	.DESCRIPTION
		Removes the NDC string that is currently being used in the log.
		This is implied if you cal Push-LogContext the previos value is popped from the stack.
#>
function Pop-LogContext {
	$PoshLoggerInfo.CurrentLogContext = 'null'
	[log4net.NDC]::Clear() | Out-Nul
}

<#
	.SYNOPSIS
		A Replacement for Write-Debug
	.DESCRIPTION
		This command can replace the native Write-Debug. Providing a more controlled and unified logging system
	.PARAMETER  Message
		the string to log
	.PARAMETER  Logger
		an alternate Logger to use else the default is used
	.EXAMPLE
		PS C:\> Write-Debug -Message "Testing Falied" -Logger $MyLogger
	.INPUTS
		System.String,log4net.Core.LogImpl
	.OUTPUTS
		Can write to many different streams at once Console, File, Database, EventLog, Etc.
#>
function Write-Debug {
	[CmdletBinding()]
	param(
		[Parameter(Mandatory=$true, ValueFromPipeline=$true)]
		[Alias('Msg')]
		[AllowEmptyString()]
		[System.String]
		$Message,
		[Parameter(Mandatory=$false)]
		[log4net.Core.LogImpl]
		$Logger
	)

	begin {
		try {
			if($PSBoundParameters.ContainsKey("Logger")){
				$script:UseLogger = $Logger
				$null = $PSBoundParameters.Remove("Logger")
			} 
			else { 
				$script:UseLogger = $PoshLoggerInfo.DefaultLogger 
			}
		} 
		catch {Throw}
	}

	process {
		try {
			if(( Test-ConsolePrintLog ) -and ( $script:UseLogger.Logger.Level.Value -eq [PoshLogger.PoshLoggerLevel]::DEBUG.value__ )){
				$LogString = Get-LogString -LoggerName "$( $script:UseLogger.Logger.Name )" -Level 'DEBUG' -Message "$Message"
				$FuncParam = @{ 'Object' = "$LogString" ; 'ForegroundColor' = 'Green' }
				& ( $PoshLoggerInfo.NativeWriteHost ) @FuncParam
			}
			$script:UseLogger.debug($Message)
		} 
		catch {
			Throw $_
		}
	}

	end {
		try {} 
		catch { Throw }
	}
}

<#
	.SYNOPSIS
		A Replacement for Write-Verbose
	.DESCRIPTION
		This command can replace the native Write-Verbose. Providing a more controlled and unified logging system
	.PARAMETER  Message
		the string to log
	.PARAMETER  Logger
		an alternate Logger to use else the default is used
	.EXAMPLE
		PS C:\> Write-Verbose -Message "Testing Falied" -Logger $MyLogger
	.INPUTS
		System.String,log4net.Core.LogImpl
	.OUTPUTS
		Can write to many different streams at once Console, File, Database, EventLog, Etc.
	.NOTES
		Verbose is not a supported level with log4net so we are just calling our Write-Debug Functions
#>
function Write-Verbose {

	[CmdletBinding()]
	param(
		[Parameter(Mandatory=$true, ValueFromPipeline=$true)]
		[Alias('Msg')]
		[AllowEmptyString()]
		[System.String]
		$Message,
		[Parameter(Mandatory=$false)]
		[log4net.Core.LogImpl]
		$Logger
	)

	begin {
		try {
			if($PSBoundParameters.ContainsKey("Logger")){
				$script:UseLogger = $Logger
				$null = $PSBoundParameters.Remove("Logger")
			} 
			else{ 
				$script:UseLogger = $PoshLoggerInfo.DefaultLogger 
			}
		} 
		catch {Throw}
	}

	process {
		try {
			$Func = Get-Command -CommandType Function -Name "Write*Debug" -Module PoshLogger
			$FuncParam['Message'] = $Message
			& $Func @FuncParam
		}
		catch {
			Throw $_
		}
	}

	end {
		try {} 
		catch { Throw }
	}
}

<#
	.SYNOPSIS
		A Replacement for Write-Warning
	.DESCRIPTION
		This command can replace the native Write-Warning. Providing a more controlled and unified logging system
	.PARAMETER  Message
		the string to log
	.PARAMETER  Logger
		an alternate Logger to use else the default is used
	.EXAMPLE
		PS C:\> Write-Warning -Message "Testing Falied" -Logger $MyLogger
	.INPUTS
		System.String,log4net.Core.LogImpl
	.OUTPUTS
		Can write to many different streams at once Console, File, Database, EventLog, Etc.
#>
function Write-Warning {
	[CmdletBinding()]
	param(
		[Parameter(Mandatory=$true, ValueFromPipeline=$true)]
		[Alias('Msg')]
		[AllowEmptyString()]
		[System.String]
		$Message,
		[Parameter(Mandatory=$false)]
		[log4net.Core.LogImpl]
		$Logger
	)

	begin {
		try {
			if($PSBoundParameters.ContainsKey("Logger")){
				$script:UseLogger = $Logger
				$null = $PSBoundParameters.Remove("Logger")
			} 
			else{ 
				$script:UseLogger = $PoshLoggerInfo.DefaultLogger 
			}
		} 
		catch {Throw}
	}

	process {
		try {
			if(( Test-ConsolePrintLog ) -and ( $script:UseLogger.Logger.Level.Value -le [PoshLogger.PoshLoggerLevel]::WARNING.value__ )){
				$LogString = Get-LogString -LoggerName "$( $script:UseLogger.Logger.Name )" -Level 'WARN' -Message "$Message"
				$FuncParam = @{ 'Object' = "$LogString" ; 'ForegroundColor' = 'Yellow' }
				& ( $PoshLoggerInfo.NativeWriteHost ) @FuncParam
			}
			$script:UseLogger.warn($Message)
		} 
		catch {
			Throw $_
		}
	}

	end {
		try {} 
		catch { Throw }
	}
}

<#
	.SYNOPSIS
		A Replacement for Write-Error
	.DESCRIPTION
		This command can replace the native Write-Error. Providing a more controlled and unified logging system
	.PARAMETER  Message
		the string to log
	.PARAMETER  Exception
		an alternate exception to throw
	.PARAMETER  Logger
		an alternate Logger to use else the default is used
	.EXAMPLE
		PS C:\> Write-Error -Message "Testing Falied" -Exception ( New-Object System.NullReferenceException )
	.INPUTS
		System.String,System.Exception,log4net.Core.LogImpl
	.OUTPUTS
		Can write to many different streams at once Console, File, Database, EventLog, Etc.
#>
function Write-Error {
	[CmdletBinding()]
	param(
		[Parameter(Mandatory=$true,ValueFromPipeline=$true)]
		[Alias('Msg')]
		[AllowNull()]
		[AllowEmptyString()]
		[System.String]
		$Message,
		[Parameter(Mandatory=$false)]
		[System.Exception]
		$Exception = $( New-Object System.Exception ),
		[switch]
		$Fatal,
		[Parameter(Mandatory=$false)]
		[log4net.Core.LogImpl]
		$Logger
	)

	begin {
		try {
			if($PSBoundParameters.ContainsKey("Logger")){
				$script:UseLogger = $Logger
				$null = $PSBoundParameters.Remove("Logger")
			} 
			else{ 
				$script:UseLogger = $PoshLoggerInfo.DefaultLogger 
			}
		} 
		catch {Throw}
	}

	process {
		try {
			if(( Test-ConsolePrintLog ) -and ( $script:UseLogger.Logger.Level.Value -le [PoshLogger.PoshLoggerLevel]::ERROR.value__ )){
				$LogString = Get-LogString -LoggerName "$( $script:UseLogger.Logger.Name )" -Level 'ERROR' -Message "$Message"
				$FuncParam = @{ 'Object' = "$LogString" ; 'ForegroundColor' = 'Red' }
				if( $PSBoundParameters.ContainsKey('Fatal') ){ $FuncParam['BackgroundColor'] = 'White' }
				& ( $PoshLoggerInfo.NativeWriteHost ) @FuncParam
			}
			if( $PSBoundParameters.ContainsKey('Fatal') ){
				$PoshLoggerInfo.DefaultLogger.Fatal($Message,$Exception)
			}
			else{
				$script:UseLogger.error($Message,$Exception)
			}
		} 
		catch {
			Throw $_
		}
	}

	end {
		try{}
		catch{}
	}
}

<#
	.SYNOPSIS
		Write-Info is the command Write-Host is aliased to.
	.DESCRIPTION
		Write-Info Replacement for Write-Host (there is an alias mapping) that uses log4net to control how and where logging occurs
	.PARAMETER  Object
		Any objects recieved form the command line or pipline
	.PARAMETER  Logger
		The logger to use for the log operation if not specified uses default logger
	.EXAMPLE
		PS C:\> Write-Host -Object "Hello World"
	.INPUTS
		System.Object,log4net.Core.LogImpl
	.OUTPUTS
		Can write to many different streams at once Console, File, Database, EventLog, Etc.
#>
function Write-Info {
	[CmdletBinding()]
	param(
		[Parameter(Mandatory=$true,ValueFromPipeline=$true)]
		[Alias('Msg')]
		[AllowNull()]
		[AllowEmptyString()]
		[System.String]
		$Message,
		[Parameter(Mandatory=$false)]
		[log4net.Core.LogImpl]
		$Logger
	)

	begin {
		try {
			if($PSBoundParameters.ContainsKey("Logger")){
				$script:UseLogger = $Logger
				$null = $PSBoundParameters.Remove("Logger")
			} 
			else{ 
				$script:UseLogger = $PoshLoggerInfo.DefaultLogger 
			}
		} 
		catch {Throw}
	}

	process {
		try {
			if(( Test-ConsolePrintLog ) -and ( $script:UseLogger.Logger.Level.Value -le [PoshLogger.PoshLoggerLevel]::INFO.value__ )){
				$LogString = Get-LogString -LoggerName "$( $script:UseLogger.Logger.Name )" -Level 'INFO' -Message "$Message"
				$FuncParam = @{ 'Object' = "$LogString" ; 'ForegroundColor' = 'Cyan' }
				& ( $PoshLoggerInfo.NativeWriteHost ) @FuncParam

			}
			$script:UseLogger.info($Message)
		} 
		catch { 
			Throw $_
		}
	}

	end {
		try {} 
		catch { Throw }
	}
}

<#
	.SYNOPSIS
		Provides an easy interface for logging
	.DESCRIPTION
		Provides an easy interfaces for logging by providing the message and log level. 
		This will use the default logger.
	.PARAMETER  Message
		The Message string to log
	.PARAMETER  LogLevel
		'DEBUG','INFO','WARN','ERROR'
	.EXAMPLE
		PS C:\> Write-Log -Message 'Hello World' -LogLevel 'DEBUG' -NoConsole
	.INPUTS
		System.String, System.String, Switch
#>
function Write-Log {
	[CmdletBinding()]
	param(
		[Parameter(Position=0,Mandatory=$false)]
		[string]
		$Message = 'EMPTY MESSAGE',
		[Parameter(Position=1,Mandatory=$false)]
		[ValidateSet('DEBUG','INFO','WARN','ERROR','FATAL')]
		$LogLevel = "INFO"
	)
	
	$Func = $null
	$FuncParam = @{}
	
	switch( ( $LogLevel.ToLower() )[0] ){
		"e"{
			$Func = @( Get-Command -CommandType Function -Name "Write*Error" -Module PoshLogger )[0]
			& $Func -Message $Message -Exception ( New-Object System.Exception -ArgumentList $Message )
			break
		}
		"f"{
			$Func = @( Get-Command -CommandType Function -Name "Write*Error" -Module PoshLogger )[0]
			& $Func -Message $Message -Exception ( New-Object System.Exception -ArgumentList $Message ) -Fatal
			break
		}
		"w"{
			$Func = @( Get-Command -CommandType Function -Name "Write*Warning" -Module PoshLogger )[0]
			& $Func -Message $Message
			break
		}
		"d"{
			$Func = @( Get-Command -CommandType Function -Name "Write*Debug" -Module PoshLogger )[0]
			& $Func -Message $Message
			break
		}
		default{
			$Func = @( Get-Command -CommandType Function -Name "Write*Info" -Module PoshLogger )[0]
			& $Func -Message $Message
			break
		}
	}
}
